//import cytoscape.visual.Appearance;
import java.awt.Font;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Random;

import cytoscape.CyNetwork;
import cytoscape.Cytoscape;
import cytoscape.data.CyAttributes;
import cytoscape.data.readers.VisualStyleBuilder;
import cytoscape.layout.CyLayoutAlgorithm;
import cytoscape.layout.CyLayouts;
import cytoscape.layout.algorithms.GridNodeLayout;
import cytoscape.view.CyNetworkView;
import cytoscape.visual.NodeShape;
import cytoscape.visual.VisualPropertyType;


/*******************************************************************************
 * Description: This class rebuilds the protein network in cytoscape. 
 * It paints the clusters in different colors. And apllied layout on the
 * network.
 * @author liatperl
 * Last updater: Liat Perlman
 * Date : 20/8/09
 *******************************************************************************/
public class BuildClusterNet {
	/**
	 * This function colors the clusters of the network
	 * in different colors and applys layout on it.
	 */
	public static void colorNetwork(HashMap<String, Gene> geneMap,
			LinkedList<Cluster> clusters) {
		if ((geneMap == null) || (clusters == null))
			return;
		
		
		
		//CyNetwork cyNet = Cytoscape.getCurrentNetwork();
		
		//Cytoscape.destroyNetwork(cyNet);
		
		//CyNetworkView netView = Cytoscape.createNetworkView(cyNet, "cyNet");
		CyNetworkView netView = Cytoscape.getCurrentNetworkView();
		// clear the network if you already used it.
		//CyNetwork curNet =  Cytoscape.getCurrentNetwork();
		//netView.applyLayout(new GridNodeLayout());
		//netView.redrawGraph(false, true);
		
		Gene gene;
		int clusterNum =0;

		// TODO: change when have attributes.
		String attributeName = "funcClass";
		CyAttributes cyNodeAttr = Cytoscape.getNodeAttributes();
		
		// initialize the attributes if this ins not the first use.
		
		//NodeView nodeView;
		// add a number to change the style each time
		String styleName = "myVisualStyle";	
		VisualStyleBuilder graphStyle = new VisualStyleBuilder(styleName, false);
		graphStyle.setNodeSizeLocked(false);
		String colorStr;
		int redInt =0;
		int greenInt= 0;	
		int blueInt=0;
		//CyNode curNode;
		Random rand = new Random();

		// go over each cluster and color the right nodes with a matching color.
		Iterator<Gene> iter = null;		
		for (Cluster clus: clusters) {
			iter  = clus.iterator();
			int colorMaxLimit = 256;
			int whiteMinLimit = 250;
			int blackMinLimit = 5;
			// if the color is similar to white or black don't choose this color.
			// continue to choose colors different than white and black.
			do {
				redInt = rand.nextInt(colorMaxLimit);
				greenInt = rand.nextInt(colorMaxLimit);	
				blueInt = rand.nextInt(colorMaxLimit);
				//System.out.println("redInt:"+redInt+" greenInt:"+greenInt+" blueInt:"+blueInt);
			} while ( ((whiteMinLimit <= redInt) && (whiteMinLimit <= greenInt) && (whiteMinLimit <= blueInt)) 
					|| ((redInt <= blackMinLimit) && (greenInt <= blackMinLimit) && (blueInt <=blackMinLimit) ));

			//}
			colorStr = "#"+Integer.toHexString(redInt)+Integer.toHexString(greenInt)+Integer.toHexString(blueInt);
			while ( iter.hasNext()) {
				gene  = iter.next();
				// remove all nodes that have a cluster.
				graphStyle.addProperty(gene.getName(),VisualPropertyType.NODE_FILL_COLOR, colorStr);
				graphStyle.addProperty(gene.getName(),VisualPropertyType.NODE_LABEL, gene.getName());
				graphStyle.addProperty(gene.getName(),VisualPropertyType.NODE_SHAPE, NodeShape.ELLIPSE.getShapeName());
				graphStyle.addProperty(gene.getName(),VisualPropertyType.NODE_FONT_FACE, new Font("SansSerif.bold", Font.BOLD,18).getFontName());
				graphStyle.addProperty(gene.getName(),VisualPropertyType.NODE_WIDTH, "70");
				graphStyle.addProperty(gene.getName(),VisualPropertyType.NODE_HEIGHT, "70");
				//appear.set(VisualPropertyType.NODE_FILL_COLOR, curColor);
				//appear.set(VisualPropertyType.NODE_LABEL, node.getName());
				//appear.applyAppearance(nodeView);
				// set the func attribute to the node. The node should have
				// the annotation of the cluster.
				//System.out.println("cluster annotation:"+clus.getAnnotation());
				cyNodeAttr.setAttribute(gene.getName(), attributeName, clus.getAnnotation());
			}
			clusterNum++;
		}

		// all the remaining nodes are ones that don't have any clusters.
		// color all these nodes in white.
		String whiteColor = "#"+Integer.toHexString(255)+Integer.toHexString(255)+Integer.toHexString(255);
		for (Gene currGene: geneMap.values()) {
			if (currGene.clustersCount() == 0) {
				graphStyle.addProperty(currGene.getName(),VisualPropertyType.NODE_FILL_COLOR, whiteColor);
				graphStyle.addProperty(currGene.getName(),VisualPropertyType.NODE_LABEL, currGene.getName());
				graphStyle.addProperty(currGene.getName(),VisualPropertyType.NODE_SHAPE, NodeShape.ELLIPSE.getShapeName());
				graphStyle.addProperty(currGene.getName(),VisualPropertyType.NODE_FONT_FACE, new Font("SansSerif.bold", Font.BOLD,18).getFontName());
				graphStyle.addProperty(currGene.getName(),VisualPropertyType.NODE_WIDTH, "70");
				graphStyle.addProperty(currGene.getName(),VisualPropertyType.NODE_HEIGHT, "70");
				cyNodeAttr.setAttribute(currGene.getName() , attributeName, "");// the annotation of unannotated proteins should be the
				// empty string.
			}
		}

		graphStyle.buildStyle();
		// set the view in the graph.
		Cytoscape.getCurrentNetworkView().redrawGraph(false, true);

		// do layout according to the GO annotation of the cluster.		
		final CyNetwork currNetwork = Cytoscape.getCurrentNetwork();


		CyLayoutAlgorithm layoutAlgorithm = CyLayouts.getLayout("attributes-layout");
		CyNetworkView currNetworkView = Cytoscape.getNetworkView(currNetwork.getIdentifier());

		if ((layoutAlgorithm != null) && (currNetworkView != null)) {
			layoutAlgorithm.setLayoutAttribute(attributeName); 
			layoutAlgorithm.doLayout(currNetworkView); 
		} 
		// inform others via property change event.
		Cytoscape.firePropertyChange(Cytoscape.ATTRIBUTES_CHANGED, null, null);
		final CyNetworkView networkView = Cytoscape.getCurrentNetworkView(); 
		networkView.setZoom(0.50);
		networkView.updateView(); 
	}
	
	
}
